// 11.1.2 处理成员函数及额外的参数
// 在泛型编程中，处理成员函数和额外参数是一个常见的挑战。这一节探讨了如何在泛型代码中优雅地处理成员函数调用和额外参数传递。

// 成员函数的特殊性
// 成员函数与普通函数的主要区别在于：
// 成员函数需要一个对象实例（this指针）
// 调用语法不同（obj.method() 或 ptr->method()）
// 这使得在泛型代码中统一处理普通函数和成员函数变得复杂。

// 处理成员函数的技术
// 1. 使用函数适配器
template <typename Class, typename ReturnType, typename... Args>
auto make_member_function_wrapper(ReturnType (Class::*func)(Args...), Class *instance)
{
    return [func, instance](Args... args) -> ReturnType
    {
        return (instance->*func)(std::forward<Args>(args)...);
    };
}

// 使用示例
class MyClass
{
public:
    int multiply(int a, int b) { return a * b; }
};

MyClass obj;
auto wrapper = make_member_function_wrapper(&MyClass::multiply, &obj);
int result = wrapper(5, 6); // 调用 obj.multiply(5, 6)

// 2. 使用 std::mem_fn
// std::mem_fn 是一个将成员函数转换为函数对象的工具：
class Button
{
public:
    void click() { std::cout << "Button clicked!" << std::endl; }
};

std::vector<Button> buttons(5);
// 对每个按钮调用click方法
std::for_each(buttons.begin(), buttons.end(), std::mem_fn(&Button::click));

// 3. 使用 std::bind
class Processor
{
public:
    int process(int a, int b, int c) { return a + b + c; }
};

Processor proc;
// 绑定成员函数和对象，固定第一个参数
auto bound = std::bind(&Processor::process, &proc, 10, std::placeholders::_1, std::placeholders::_2);
int result = bound(20, 30); // 调用 proc.process(10, 20, 30)

// 处理额外参数
// 在泛型代码中，经常需要处理可变数量的额外参数。
// 1. 使用可变参数模板
template <typename Callable, typename... ExtraArgs>
class DelayedInvoker
{
private:
    Callable func;
    std::tuple<ExtraArgs...> args;

public:
    DelayedInvoker(Callable f, ExtraArgs... extraArgs)
        : func(f), args(std::make_tuple(extraArgs...)) {}

    template <typename... CallArgs>
    auto invoke(CallArgs &&...callArgs)
    {
        return apply_with_extra_args(func, args, std::forward<CallArgs>(callArgs)...);
    }
};

// 辅助函数，将额外参数和调用参数合并
template <typename Func, typename Tuple, typename... CallArgs, size_t... I>
auto apply_with_extra_args_impl(Func &&f, Tuple &t, std::index_sequence<I...>, CallArgs &&...callArgs)
{
    return std::invoke(std::forward<Func>(f), std::get<I>(t)..., std::forward<CallArgs>(callArgs)...);
}

template <typename Func, typename Tuple, typename... CallArgs>
auto apply_with_extra_args(Func &&f, Tuple &t, CallArgs &&...callArgs)
{
    return apply_with_extra_args_impl(
        std::forward<Func>(f), t,
        std::make_index_sequence<std::tuple_size_v<Tuple>>(),
        std::forward<CallArgs>(callArgs)...);
}

// 2. 使用 std::bind 和占位符
template <typename Func, typename... BoundArgs>
auto bind_front(Func &&f, BoundArgs &&...args)
{
    return [f = std::forward<Func>(f), bound_args = std::make_tuple(std::forward<BoundArgs>(args)...)]<typename... CallArgs>(CallArgs &&...call_args) mutable
    {
        return std::apply([&](auto &&...bound)
                          { return std::invoke(f, std::forward<decltype(bound)>(bound)...,
                                               std::forward<CallArgs>(call_args)...); }, bound_args);
    };
}

// 使用示例
void print(int a, int b, int c)
{
    std::cout << a << ", " << b << ", " << c << std::endl;
}

auto bound = bind_front(print, 10);
bound(20, 30); // 输出: 10, 20, 30

// 在C++17/20中的改进
// C++17引入了std::invoke，它统一了函数调用语法：
template <typename Callable, typename... Args>
auto call(Callable &&func, Args &&...args)
{
    return std::invoke(std::forward<Callable>(func), std::forward<Args>(args)...);
}

// 可以统一调用普通函数、成员函数、函数对象等
int value = 42;
call(print, 1, 2, 3);            // 调用普通函数
call(&MyClass::method, obj, 10); // 调用成员函数
call([](int x)
     { return x * x; }, 5); // 调用lambda
